package com.fingard.net;

import com.fingard.FGBiz;
import com.fingard.diagnostics.LogHelper;
import com.fingard.dsp.bank.directConfig.FtpSet;
import com.fingard.generalobj.ExecResponse;
import com.fingard.text.StringHelper;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

public class FtpPortClient {

    private FtpSet ftpSet;
    public StringBuilder sbLog;
    //是否启用被动模式
    private boolean isLocalPassiveMode = false;
    public FtpPortClient(FtpSet p_ftpSet) {
        ftpSet = p_ftpSet;
        connReceiver = new FtpReceiver();
        ftpClient = new FTPClient();
        isExecutedConnect = false;
        arFiles = new ArrayList<String>();
        sbLog = new StringBuilder();
    }

    private FTPClient ftpClient;
    private FtpReceiver connReceiver;
    private boolean isExecutedConnect;//是否执行过connect()

    /**
     * 目录分割符
     */
    private final String SEPARATOR = "/";

    /**
     * 空格
     */
    private final String blank = " ";

    /**
     * FTP目录标识
     */
    private final String directoryFlag = "..";

    public ArrayList<String> arFiles;

    public ExecResponse connect() throws IOException {
    	ExecResponse resp = new ExecResponse();
        isExecutedConnect = true;
        try {
            if (FGBiz.dspCenter.dspSet.enableFtpPassiveMode) {
                ftpClient.enterLocalPassiveMode();
            }
            ftpClient.connect(ftpSet.serverIP, ftpSet.port);
            boolean loginResult = ftpClient.login(ftpSet.userName, ftpSet.userPassword);
            //ftpClient.setBufferSize(1024);
            ftpClient.setControlEncoding(ftpSet.charset);
            //ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);

            // 检验是否连接成功
            int reply = ftpClient.getReplyCode();
            if (!loginResult || !FTPReply.isPositiveCompletion(reply)) {
                connReceiver.connState = ConnState.FAIL;
                connReceiver.connMsg = "登录失败";
                ftpClient.disconnect();
                //return retReceiver;
                resp.isSucceed = false;
                resp.logMsg = connReceiver.connMsg;
                resp.setResult(connReceiver.connMsg);
            } else if (isLocalPassiveMode) {
                ftpClient.enterLocalPassiveMode();
                resp.isSucceed = true;
            }else{
            	resp.isSucceed = true;
            }
        } catch (Exception ex) {
            //ex.printStackTrace();
        	FGBiz.limitMsg.exception("FtpPortClient.connect", ex);
            connReceiver.connState = ConnState.FAIL;
            connReceiver.connMsg = LogHelper.getStackTrace(ex);//ex.getMessage();
            disconnect();
            //return retReceiver;
            resp.isSucceed = false;
            resp.logMsg = connReceiver.connMsg;
            resp.setResult(LogHelper.getStackTraceFirstLine(ex));
        }
        return resp;
    }

    public void disconnect() throws IOException {
        try {
            if (ftpClient != null && ftpClient.isConnected()) {
                ftpClient.disconnect();
            }
        } catch (Exception ex) {
        	String exMsg = "";
        	if(ftpSet != null){
        		exMsg = ftpSet.serverIP+":"+ftpSet.port;
        	}
            FGBiz.limitMsg.exception("FtpPortClient.disconnect", ex, exMsg);
        }
    }

    private String nowWorkingDirectory = "";
    
    public FtpReceiver uploadFile(String p_localFile, String p_trgFileName) throws IOException {
    	return uploadFileToDir(p_localFile, ftpSet.upDir, p_trgFileName);
    }

    /**上传本地文件到指定目录，如果目录不存在则先创建目录*/
    public FtpReceiver uploadFileToDir(String p_localFile,String pUpDir, String p_trgFileName) throws IOException {
        if (!isExecutedConnect) {
            connect();
        }
        if (connReceiver.connState.length() > 0) {
            return connReceiver;
        }
        //取消服务器获取自身Ip地址和提交的host进行匹配
        ftpClient.setRemoteVerificationEnabled(false);
        FtpReceiver retReceiver = new FtpReceiver();
        FileInputStream in = null;
        try {
        	ExecResponse respMk = makeDirIfNotExist(pUpDir);
        	if(!respMk.isSucceed){
        		retReceiver.isCompleted = false;
                retReceiver.connMsg = "目录" + pUpDir + "创建失败："+respMk.logMsg;
        	}
            if (!nowWorkingDirectory.equals(pUpDir)) {
                // 转移工作目录至指定目录下
                boolean change = ftpClient.changeWorkingDirectory(pUpDir);
                if (!change) {
                    //createFolder(ftpClient,path);
                    //ftpClient.changeWorkingDirectory(path);
                    retReceiver.connState = ConnState.FAIL;
                    retReceiver.connMsg = "目录" + pUpDir + "不存在";
                    //ftpClient.disconnect();
                    return retReceiver;
                }
                nowWorkingDirectory = pUpDir;
            }
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            in = new FileInputStream(p_localFile);
            boolean upResult = ftpClient.storeFile(p_trgFileName, in);
            if (upResult) {
                retReceiver.isCompleted = true;
            }
        } catch (Exception ex) {
            retReceiver.connMsg = LogHelper.getStackTrace(ex);//ex.getMessage();
        } finally {
            if (in != null) {
                in.close();
            }
            //if(ftpClient.isConnected()){
            //	ftpClient.disconnect();
            //}
        }
        return retReceiver;
    }

    public FtpReceiver downloadFile(String p_downFileName, String p_saveLocalFile) throws IOException {
    	this.sbLog = new StringBuilder();
        if (!isExecutedConnect) {
            connect();
        }
        if (connReceiver.connState.length() > 0) {
            return connReceiver;
        }
        FtpReceiver retReceiver = new FtpReceiver();
        FileOutputStream saveStream = null;
        try {
            if (!nowWorkingDirectory.equals(ftpSet.downDir)) {
                // 转移工作目录至指定目录下
                boolean change = ftpClient.changeWorkingDirectory(ftpSet.downDir);
                if (!change) {
                    //createFolder(ftpClient,path);
                    //ftpClient.changeWorkingDirectory(path);
                    retReceiver.connState = ConnState.FAIL;
                    retReceiver.connMsg += "目录" + ftpSet.downDir + "不存在\r\n";
                    //ftpClient.disconnect();
                    return retReceiver;
                }
                nowWorkingDirectory = ftpSet.downDir;
            }
            boolean setResult = ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            sbLog.append("setFileType:"+setResult);
        	ftpClient.enterLocalPassiveMode();
        	sbLog.append("enterLocalPassiveMode");
            File tmpFile = new File(p_saveLocalFile);
            File parentDir = new File(tmpFile.getParent());
            if (!parentDir.exists()) {
                parentDir.mkdirs();
                sbLog.append("mkdirs:"+parentDir.getAbsolutePath());
            }
            if (!tmpFile.exists()) {
                tmpFile.createNewFile();
            }
            saveStream = new FileOutputStream(p_saveLocalFile);
            boolean downResult = ftpClient.retrieveFile(StringHelper.getFileName(p_downFileName), saveStream);
            if (downResult) {
                retReceiver.isCompleted = true;
                sbLog.append("retrieveFile:"+downResult);
            }else{
            	retReceiver.connState = ConnState.FILE_NOT_EXISTS;
            	retReceiver.connMsg +="下载:["+StringHelper.getFileName(p_downFileName)+"]失败,服务器文件不存在，无法进行下载!";
            	
            	downResult = ftpClient.retrieveFile(p_downFileName, saveStream);
            	if (downResult) {
                    retReceiver.isCompleted = true;
                    retReceiver.connMsg = "下载成功";
            	}
            	/*else{
            		retReceiver.connMsg +="下载"+p_downFileName+"失败\r\n";
            	}*/
            }
        } catch (Exception ex) {
            retReceiver.connMsg += LogHelper.getStackTrace(ex)+"\r\n";//ex.getMessage();
        } finally {
            if (saveStream != null) {
                saveStream.close();
            }
            //if(ftpClient.isConnected()){
            //	ftpClient.disconnect();
            //}
        }
        return retReceiver;
    }
    
    /**从指定目录下载文件*/
    public FtpReceiver downloadFileFromDir(String pDownDir, String pDownFileName, String pSaveLocalFile) throws IOException {
    	//this.sbLog = new StringBuilder();
        if (!isExecutedConnect) {
            connect();
        }
        if (connReceiver.connState.length() > 0) {
            return connReceiver;
        }
        FtpReceiver retReceiver = new FtpReceiver();
        FileOutputStream saveStream = null;
        try {
            if (!nowWorkingDirectory.equals(pDownDir)) {
                // 转移工作目录至指定目录下
                boolean change = ftpClient.changeWorkingDirectory(pDownDir);
                if (!change) {
                    //createFolder(ftpClient,path);
                    //ftpClient.changeWorkingDirectory(path);
                    retReceiver.connState = ConnState.FAIL;
                    retReceiver.connMsg += "目录" + pDownDir + "不存在\r\n";
                    //ftpClient.disconnect();
                    return retReceiver;
                }
                nowWorkingDirectory = pDownDir;
            }
            boolean setResult = ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            //sbLog.append("setFileType:"+setResult);
            retReceiver.connMsg+="setFileType:"+setResult+".";
        	ftpClient.enterLocalPassiveMode();
        	//sbLog.append("enterLocalPassiveMode");
            File tmpFile = new File(pSaveLocalFile);
            File parentDir = new File(tmpFile.getParent());
            if (!parentDir.exists()) {
                parentDir.mkdirs();
                //sbLog.append("mkdirs:"+parentDir.getAbsolutePath());
            }
            if (!tmpFile.exists()) {
                tmpFile.createNewFile();
            }
            saveStream = new FileOutputStream(pSaveLocalFile);
            boolean downResult = ftpClient.retrieveFile(StringHelper.getFileName(pDownFileName), saveStream);
            if (downResult) {
                retReceiver.isCompleted = true;
                //sbLog.append("retrieveFile:"+downResult);
            }else{
            	retReceiver.connState = ConnState.FILE_NOT_EXISTS;
            	retReceiver.connMsg +="下载:["+StringHelper.getFileName(pDownFileName)+"]失败,服务器文件不存在，无法进行下载!";
            	
            	downResult = ftpClient.retrieveFile(pDownFileName, saveStream);
            	if (downResult) {
                    retReceiver.isCompleted = true;
                    retReceiver.connMsg = "下载成功";
            	}
            	/*else{
            		retReceiver.connMsg +="下载"+p_downFileName+"失败\r\n";
            	}*/
            }
        } catch (Exception ex) {
            retReceiver.connMsg += LogHelper.getStackTrace(ex)+"\r\n";//ex.getMessage();
        } finally {
            if (saveStream != null) {
                saveStream.close();
            }
            //if(ftpClient.isConnected()){
            //	ftpClient.disconnect();
            //}
        }
        return retReceiver;
    }


    public FtpReceiver deleteFile(String deleteFilePath) throws IOException {
        this.sbLog = new StringBuilder();
        if (!isExecutedConnect) {
            connect();
        }
        if (connReceiver.connState.length() > 0) {
            return connReceiver;
        }
        FtpReceiver retReceiver = new FtpReceiver();
        FileOutputStream saveStream = null;
        try {
            if (!nowWorkingDirectory.equals(ftpSet.downDir)) {
                // 转移工作目录至指定目录下
                boolean change = ftpClient.changeWorkingDirectory(ftpSet.downDir);
                if (!change) {
                    //createFolder(ftpClient,path);
                    //ftpClient.changeWorkingDirectory(path);
                    retReceiver.connState = ConnState.FAIL;
                    retReceiver.connMsg += "目录" + ftpSet.downDir + "不存在\r\n";
                    //ftpClient.disconnect();
                    return retReceiver;
                }
                nowWorkingDirectory = ftpSet.downDir;
            }
              boolean delResult = ftpClient.deleteFile(deleteFilePath);
            if (delResult) {
                retReceiver.isCompleted = true;
                sbLog.append("deleteFile:"+deleteFilePath);
            }else{
                retReceiver.connState = ConnState.FILE_NOT_EXISTS;
                retReceiver.connMsg +="删除:["+StringHelper.getFileName(deleteFilePath)+"]失败,服务器文件不存在，无法进行下载!";
                delResult = ftpClient.deleteFile(deleteFilePath);
                if (delResult) {
                    retReceiver.isCompleted = true;
                    retReceiver.connMsg = "下载成功";
                }
            }
        } catch (Exception ex) {
            retReceiver.connMsg += LogHelper.getStackTrace(ex)+"\r\n";//ex.getMessage();
        } finally {
            if (saveStream != null) {
                saveStream.close();
            }
        }
        return retReceiver;
    }


    /**
     * 递归遍历出目录下面所有文件
     *
     * @param pathName 需要遍历的目录，必须以"/"开始和结束
     * @throws IOException
     */
    public void list(String pathName) throws IOException {
        if (pathName.startsWith("/") && pathName.endsWith("/")) {
            String directory = pathName;
            //更换目录到当前目录
            ftpClient.changeWorkingDirectory(directory);
            FTPFile[] files = ftpClient.listFiles();
            for (FTPFile file : files) {
                if (file.isFile()) {
                    arFiles.add(directory + file.getName());
                } else if (file.isDirectory()) {
                    list(directory + file.getName() + "/");
                }
            }
        }
    }

    /**
     * 递归遍历出目录下面所有文件
     *
     * @param pathName 需要遍历的目录，必须以"/"开始和结束
     * @throws IOException
     */
    public void list(String pathName, boolean isListInnerDir) throws IOException {
        if (!isListInnerDir) {
            if (pathName.startsWith("/") && pathName.endsWith("/")) {
                String directory = pathName;
                //更换目录到当前目录
                ftpClient.changeWorkingDirectory(directory);
                FTPFile[] files = ftpClient.listFiles();
                for (FTPFile file : files) {
                    if (file.isFile()) {
                        arFiles.add(directory + file.getName());
                    }
                }
            }
        }else {
            list(pathName);
        }
    }

    /**
     * 递归遍历目录下面指定的文件名
     *
     * @param pathName 需要遍历的目录，必须以"/"开始和结束
     * @param ext      文件的扩展名
     * @throws IOException
     */
    public void list(String pathName, String ext) throws IOException {
        if (pathName.startsWith("/") && pathName.endsWith("/")) {
            String directory = pathName;
            //更换目录到当前目录
            ftpClient.changeWorkingDirectory(directory);
            ftpClient.enterLocalPassiveMode();
            FTPFile[] files = ftpClient.listFiles();
            for (FTPFile file : files) {
                if (file.isFile()) {
                    if (file.getName().endsWith(ext)) {
                        arFiles.add(directory + file.getName());
                    }
                } else if (file.isDirectory()) {
                    if (file.getName().endsWith(".") && file.getName().startsWith(".")) {
                        continue;
                    }
                    list(directory + file.getName() + "/", ext);
                }
            }
        }
    }

    public void setLocalPassiveMode() {
        this.isLocalPassiveMode = true;
    }

    /**
     * 判断文件是否存在
     *
     * @param remotePath 远程FTP路径
     * @return
     */
    public boolean existFile(String remotePath) {
        remotePath = StringHelper.trimStart(remotePath, SEPARATOR);
        remotePath = StringHelper.trimEnd(remotePath, SEPARATOR);
        if (StringHelper.isNullOrEmpty(remotePath)) {
            return false;
        }
        boolean flag = false;

        try {
            String status = ftpClient.getStatus(remotePath);
            String fileName = remotePath.substring(remotePath.lastIndexOf(SEPARATOR) + 1, remotePath.length());
            if (StringHelper.isNullOrEmpty(fileName)) {
                return false;
            }
            if (status!=null && status.indexOf(blank + fileName) != -1) {
                flag = true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return flag;
    }

    /**
     * 判断目录是否存在
     *
     * @param remotePath 远程FTP路径
     * @return
     */
    public boolean existDirectory(String remotePath) {
        remotePath = StringHelper.trimStart(remotePath, SEPARATOR);
        remotePath = StringHelper.trimEnd(remotePath, SEPARATOR);
        if (StringHelper.isNullOrEmpty(remotePath)) {
            return false;
        }
        boolean flag = false;

        try {
            String status = ftpClient.getStatus(remotePath);
            if (status.indexOf(blank + directoryFlag) != -1) {
                flag = true;
            }
        } catch (IOException e) {
        	FGBiz.limitMsg.exception("FtpPortClient.existDirectory", e, remotePath);
        }

        return flag;
    }
    
    public ExecResponse makeDirIfNotExist(String remotePath) {
    	ExecResponse resp = new ExecResponse();
        remotePath = StringHelper.trimEnd(remotePath, SEPARATOR);
        if (StringHelper.isNullOrEmpty(remotePath)) {
        	resp.isSucceed = false;
        	resp.logMsg = "目录为空";
            return resp;
        }

        try {
        	if (!nowWorkingDirectory.equals(remotePath)) {
                // 转移工作目录至指定目录下
                boolean change = ftpClient.changeWorkingDirectory(remotePath);
                if (!change) {
                	String[] pathSp = remotePath.split("/");
                	StringBuilder trgDir = new StringBuilder();
                	for(String eachDir : pathSp){
                		if(StringHelper.isNullOrEmpty(eachDir)){
                			continue;
                		}
                		trgDir.append("/"+eachDir);
                		change = ftpClient.changeWorkingDirectory(trgDir.toString());
                		if(!change){
                			resp.isSucceed = ftpClient.makeDirectory(trgDir.toString());
                			if(!resp.isSucceed){
                        		resp.logMsg = "创建ftp目录："+trgDir.toString()+"失败";
                        		return resp;
                        	}
                			change = ftpClient.changeWorkingDirectory(trgDir.toString());
                		}
                		if(change){
                			nowWorkingDirectory = trgDir.toString();	
                		}else{
                			resp.logMsg = "进入ftp目录"+trgDir.toString()+"失败";
                    		return resp;
                		}
                	}
                }
            }
        	resp.isSucceed = true;
        	return resp;
        	/*
            String status = ftpClient.getStatus(remotePath);
            if (status!=null && status.indexOf(blank + directoryFlag) != -1) {
            	resp.isSucceed = true;
                return resp;
            }else{
            	String[] pathSp = remotePath.split("/");
            	StringBuilder trgDir = new StringBuilder();
            	for(String eachDir : pathSp){
            		if(StringHelper.isNullOrEmpty(eachDir)){
            			continue;
            		}
            		trgDir.append("/"+eachDir);
            		status = ftpClient.getStatus(trgDir.toString());
            		if (status!=null && status.indexOf(blank + directoryFlag) != -1) {
            			continue;
            		}else{
            			resp.isSucceed = ftpClient.makeDirectory(trgDir.toString());
            			if(!resp.isSucceed){
                    		resp.logMsg = "创建ftp目录失败";
                    		return resp;
                    	}
            		}
            	}
            	resp.isSucceed = true;
            	return resp;
            }*/
        } catch (IOException e) {
        	resp.isSucceed = false;
        	resp.logMsg = LogHelper.getStackTrace(e);
        	FGBiz.limitMsg.exception("FtpPortClient.makeDirIfNotExist", e, remotePath);
        }

        return resp;
    }
  
    public void refreshArlist(){
        arFiles=new ArrayList<String>();
    }

    public FtpReceiver listFiles(String directory) throws Exception {
    	FtpReceiver retReceiver = new FtpReceiver();
    	
    	try {
	    	if (!isExecutedConnect) {
	            connect();
	        }
	        if (connReceiver.connState.length() > 0) {
	            return connReceiver;
	        }
            boolean change = ftpClient.changeWorkingDirectory(directory);
            if (!change) {
                retReceiver.connState = ConnState.FAIL;
                retReceiver.connMsg = "目录" + directory + "不存在";
                return retReceiver;
            }
            
    	    FTPFile[] fileList = ftpClient.listFiles();
    	    /*if (fileList.length < 2) {
	    		retReceiver.isCompleted = false;
	    		retReceiver.connState = ConnState.FILE_NOT_EXISTS;
	    	    retReceiver.connMsg = "FTP目录暂时生成文件";
	    	    return retReceiver;
	    	}*/
    	    
    	    StringBuilder fileNameBuilder = new StringBuilder();
    	    for(FTPFile file : fileList) {
    	    	if (file.isFile()) {
    	    	    if (fileNameBuilder.length() > 0) {
                        fileNameBuilder.append(",");
                    }
    	    		fileNameBuilder.append(file.getName());
                } else if (file.isDirectory()) {
                    // 需要加此判断。否则，ftp默认将‘项目文件所在目录之下的目录（./）’与‘项目文件所在目录向上一级目录下的目录（../）’都纳入递归，这样下去就陷入一个死循环了。需将其过滤掉。
                    if (!".".equals(file.getName()) && !"..".equals(file.getName())) {
                    	listFiles(file.getName() + "/");
                    }
                }
    	    }
    	    
    	    retReceiver.isCompleted = true;
    	    retReceiver.connMsg = fileNameBuilder.toString();
        } catch (Exception ex) {
            retReceiver.connMsg = ex.getMessage();
        } 
        
	    return retReceiver;
    }
    
    /**取得目录下的所有文件名或子目录名*/
    public ArrayList<String> listNames(String directory) throws Exception {
    	if (!isExecutedConnect) {
            connect();
        }
        if (connReceiver.connState.length() > 0) {
        	throw new Exception(connReceiver.connState+"-"+connReceiver.connMsg);
        }
        boolean change = ftpClient.changeWorkingDirectory(directory);
        if (!change) {
        	throw new Exception("目录" + directory + "不存在");
        }
        ArrayList<String> retNames = new ArrayList<String>();
        FTPFile[] fileList = ftpClient.listFiles();    
        for(FTPFile file : fileList) {
        	if (!".".equals(file.getName()) && !"..".equals(file.getName())) {
        		retNames.add(file.getName());
            }
        }
        return retNames;
    }
}
